/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = frssl_task_do.c                                    */
/*  NOTE      =                                                    */
/*  DATE      = 2016/03/31 by guojq                                 */
/*******************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

#include "frcomm.h"
#include "frlog.h"
#include "frmem.h"
#include "frlist.h"
#include "frhash2.h"

#include "frdssl.h"
#include "frssl.h"
#include "frssl_config.h"
#include "frssl_task_do.h"
#include "frssl_decode.h"

#define FRSSL_CT_HASH_SIZE    10240
//超时清除时间(秒)
#define FRSSL_CT_TIMEOUT      1200
#define FRSSL_HASH_OVER_FLOW  1024000

typedef struct __ssl_thread_lst {
    Frlist_header *p_lst_header;
    int i_index;
} Frssl_thread_lst;

typedef struct __ssl_hash_index {
    int i_sip;
    int i_dip;
    int i_dport;
    int i_index;
    struct timeval st_time;
} Frssl_hash_index;

FR_STATIC pthread_spinlock_t   g_spin_ssl_lock;
//任务链表
FR_STATIC Frlist_header  *g_p_st_dssl_thread = NULL;
//调度任务的hash
FR_STATIC Frhash_header  *g_p_st_hash_ct=NULL;
//超时时间
FR_STATIC struct timeval g_st_timeout;
//任务数
FR_STATIC int g_i_task_count = 0;

FR_STATIC void __ssl_thread_free(Frssl_thread **pp_ssl_thread)
{
    Frssl_thread *p_ssl_thread = NULL;
    
    if (pp_ssl_thread == NULL || *pp_ssl_thread == NULL)
        return;
    p_ssl_thread = *pp_ssl_thread;
    if (p_ssl_thread->p_encode)
        frfree(p_ssl_thread->p_encode);
    frfree(p_ssl_thread);
    *pp_ssl_thread = NULL;
    
    return;
}

/*******************************************************************************
*  FUNC     :  节点内存释放
*  ARGS     :  p_st_node  (Frlist_node *)
*  RTN      :
*  NOTE     :  
*******************************************************************************/
FR_STATIC void __thread_node_free(Frlist_node *p_st_node)
{
    Frssl_thread *p_ssl_thread = NULL;

    if (p_st_node == NULL || p_st_node->data == NULL)
        return;
    p_ssl_thread = (Frssl_thread *)p_st_node->data;
    if (p_ssl_thread->p_encode)
        frfree(p_ssl_thread->p_encode);
    frfree(p_ssl_thread);
    return;
}

FR_STATIC void __pthread_lst_node_free(Frlist_node *p_st_node)
{
    Frssl_thread_lst *p_ssl_lst = NULL;

    if (p_st_node == NULL || p_st_node->data == NULL)
        return;
    p_ssl_lst = (Frssl_thread_lst *)p_st_node->data;
    frlist_destroy(p_ssl_lst->p_lst_header, __thread_node_free);
    frfree(p_ssl_lst);
    return;
}

FR_STATIC void __hash_node_free(Frlist_node *p_st_node)
{
    Frssl_hash_index *p_ssl_hash = NULL;

    if (p_st_node == NULL || p_st_node->data == NULL)
        return;
    p_ssl_hash = (Frssl_hash_index *)p_st_node->data;
    frfree(p_ssl_hash);
    return;
}

unsigned long frssl_task_list_count(void)
{
    Frlist_node *p_node_tmp = NULL;
    p_node_tmp = FRLIST_FIRST_NODE(g_p_st_dssl_thread);
    unsigned long ul_task_list_all = 0;
    
    while (p_node_tmp && p_node_tmp->data)
    {
        Frssl_thread_lst *p_lst_thread = (Frssl_thread_lst *)p_node_tmp->data;
        ul_task_list_all += frlist_size(p_lst_thread->p_lst_header);
        p_node_tmp = FRLIST_NEXT_NODE(p_node_tmp);
    }
    return ul_task_list_all;
}

/*******************************************************************************
*  FUNC     :  初始化管理用list
*  ARGS     :
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :
*******************************************************************************/
int frtask_info_init(void)
{
    int i_loop = 0;
    
    if (g_i_dssl_task_cnt <= 0 || g_p_st_dssl_thread != NULL)
        return FR_FAIL;
        
    g_p_st_dssl_thread = frlist_create();
    if (g_p_st_dssl_thread == NULL)
        return FR_FAIL;
    
    g_p_st_hash_ct = frhash2_create2(FRSSL_CT_HASH_SIZE);
    if (g_p_st_hash_ct == NULL)
        goto err;
    
    for (i_loop=0;i_loop<g_i_dssl_task_cnt;i_loop++)
    {
        Frlist_node *p_node = NULL;
        Frssl_thread_lst *p_st_thread_data = (Frssl_thread_lst *)frmalloc(sizeof(Frssl_thread_lst));
        
        if (p_st_thread_data == NULL)
            goto err;
            
        memset(p_st_thread_data, 0x00, sizeof(Frssl_thread_lst));
        
        p_st_thread_data->i_index = i_loop;
        p_st_thread_data->p_lst_header = frlist_create();
        p_node = frlist_node_create(p_st_thread_data);
        frlist_add_tail(g_p_st_dssl_thread, p_node);
    }
    
    pthread_spin_init(&g_spin_ssl_lock, 0);
    
    memset(&g_st_timeout, 0x00, sizeof(struct timeval));
    
    return FR_SUCC;
err:
    frlist_destroy(g_p_st_dssl_thread, __pthread_lst_node_free);
    if (g_p_st_hash_ct)
        frhash2_free(g_p_st_hash_ct, __hash_node_free);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  退出
*  ARGS     :
*  RTN      :  
*  NOTE     :
*******************************************************************************/
void frtask_info_exit(void)
{
    if (g_p_st_dssl_thread)
        frlist_destroy(g_p_st_dssl_thread, __pthread_lst_node_free);
    if (g_p_st_hash_ct)
    {
        frhash2_free(g_p_st_hash_ct, __hash_node_free);
        frfree(g_p_st_hash_ct);
    }
    g_p_st_dssl_thread = NULL;
    g_p_st_hash_ct = NULL;
    pthread_spin_destroy(&g_spin_ssl_lock);
    
    return;
}

/*******************************************************************************
*  FUNC     :  检查是否超时
*  ARGS     :  p_node           当前节点
*           :  p_data
*  RTN      :  1   (成功)
*  NOTE     :
*******************************************************************************/
FR_STATIC int __ct_check_timeout(Frlist_node* p_node, const void *p_data)
{
    Frssl_hash_index *p_hash_node = NULL;
    struct timeval *p_st_now = NULL;

    p_hash_node = (Frssl_hash_index *)p_node->data;
    p_st_now = (struct timeval *)p_data;
    
    if (p_hash_node->st_time.tv_sec < p_st_now->tv_sec)
    {
        frhash2_del(g_p_st_hash_ct, p_node, __hash_node_free);
        return 1;
    }

    return 1;
}

void frssl_check_timeout(struct timeval *p_st_timenow)
{
    if (g_st_timeout.tv_sec == 0)
    {
        g_st_timeout.tv_sec = p_st_timenow->tv_sec + FRSSL_CT_TIMEOUT;
        g_st_timeout.tv_usec = p_st_timenow->tv_usec;
        return;
    }
    if (p_st_timenow->tv_sec > g_st_timeout.tv_sec)
    {
        pthread_spin_lock(&g_spin_ssl_lock);
        frhash2_run(g_p_st_hash_ct, p_st_timenow, __ct_check_timeout);
        pthread_spin_unlock(&g_spin_ssl_lock);
        g_st_timeout.tv_sec = p_st_timenow->tv_sec + FRSSL_CT_TIMEOUT;
    }
    return;
}

/*******************************************************************************
*  FUNC     :  组成哈希用key
*  ARGS     :  ui_src    (原地址)
            :  ui_dest   (目的地址)
            :  us_dport  (目的端口)
*  RTN      :  key长度
*  NOTE     :
*******************************************************************************/
FR_STATIC int __frct_get_index(u_int ui_src, u_int ui_dest, u_short us_dport)
{
    int i_idx=0, i_len;
    char arr_hash_key[20];
    u_int *stupid_strict_aliasing_warnings=(u_int*)arr_hash_key;

    if(sizeof(arr_hash_key) <= sizeof(u_int)*2+ sizeof(u_short))
    {
        FRLOG_ERROR_DETAIL("ssl ct hash key err");
        return 0;
    }

    i_len = sizeof(u_int);
    *stupid_strict_aliasing_warnings = ui_src;
    i_idx += i_len;

    *(u_int *) (arr_hash_key + i_idx) = ui_dest;
    i_idx += i_len;

    *(u_short *) (arr_hash_key + i_idx) = us_dport;
    i_idx += i_len;

    return frhash_key((unsigned char *)arr_hash_key, i_idx) % g_i_dssl_task_cnt;
}
/*******************************************************************************
*  FUNC     :  组成哈希用key
*  ARGS     :  ui_src    (原地址)
            :  ui_dest   (目的地址)
            :  us_dport  (目的端口)
*  RTN      :  key长度
*  NOTE     :
*******************************************************************************/
FR_STATIC int __frct_hash_key(u_int ui_src, u_int ui_dest, u_short us_dport
                            , char *p_key, unsigned int ui_key_size)
{
    int i_idx=0, i_len;
    u_int *stupid_strict_aliasing_warnings=(u_int*)p_key;

    if(p_key == NULL || ui_key_size <= sizeof(u_int)*2+ sizeof(u_short)*3)
    {
        FRLOG_ERROR_DETAIL("ct hash key err");
        return 0;
    }

    i_len = sizeof(u_int);
    *stupid_strict_aliasing_warnings = ui_src;
    i_idx += i_len;

    *(u_int *) (p_key + i_idx) = ui_dest;
    i_idx += i_len;

    i_len = sizeof(u_short);
    *(u_short *) (p_key + i_idx) = us_dport;
    i_idx += i_len;

    return i_idx;
}

/*******************************************************************************
*  FUNC     :  获取连接的node
*  ARGS     :  ui_src    (原地址)
            :  ui_dest   (目的地址)
            :  us_dport  (目的端口)
*  RTN      :  节点指针:成功， NULL:失败
*  NOTE     :
*******************************************************************************/
Frlist_node *__frct_hash_get(u_int ui_src
                           , u_int ui_dest
                           , u_short us_dport)
{
    Frlist_node *p_st_node=NULL;
    char arr_hash_key[20];
    int i_hash_key_len=0;

    if(g_p_st_hash_ct==NULL)
        return NULL;

    i_hash_key_len = __frct_hash_key(ui_src, ui_dest, us_dport, arr_hash_key, sizeof(arr_hash_key));
    p_st_node = frhash2_getStr(g_p_st_hash_ct, arr_hash_key, i_hash_key_len);

    return p_st_node;
}

/*******************************************************************************
*  FUNC     :  增加ct到hash
*  ARGS     :  p_st_index_node  (Frssl_hash_index *)
            :  i_sip   
*  RTN      :  成功:返回当前ct的节点, 失败:NULL
*  NOTE     :
*******************************************************************************/
Frlist_node *__frct_hash_add(Frssl_hash_index *p_st_index_node
                           , int i_sip, int i_dip, int i_dport)
{
    Frlist_node *p_st_node=NULL;
    char arr_hash_key[20];
    int i_hash_key_len=0;
    int i_ret_fun;

    if(g_p_st_hash_ct==NULL || p_st_index_node==NULL)
        return p_st_node;

    p_st_node = frlist_node_create(p_st_index_node);
    if(!p_st_node)
        return p_st_node;

    i_hash_key_len = __frct_hash_key(i_sip, i_dip, i_dport, arr_hash_key, sizeof(arr_hash_key));

    i_ret_fun = frhash2_addStr(g_p_st_hash_ct, arr_hash_key, i_hash_key_len, p_st_node);
    if(i_ret_fun == FR_FAIL)
    {
        frfree(p_st_node);
        return NULL;
    }
    return p_st_node;
}

int frssl_task_add(u_char * p_packet, DAQ_PktHdr_t *header)
{
    sniffer_ipinfo st_ipinfo;
    int i_type = 0;
    unsigned long ul_lst_index = 0;
    Frlist_node *p_st_node=NULL;
    Frssl_thread *p_ssl_thread = NULL;
    
    //取得ip地址端口
    if (frssl_getipinfo(p_packet, &st_ipinfo, &i_type) != FR_SUCC)
        goto err;

    //查找ssl列表，跳过不需要做解码的数据包
    if (frssl_config_lookup(&st_ipinfo) == SSL_CONFIG_NOTFIND)
        goto err;

#ifdef FRTEST_REPORT
    g_ul_pcap_receive_all++;
#endif

    frssl_check_timeout(&header->ts);
    
    //取得数据的index
    {
        Frlist_node *p_st_hash_node=NULL;
        
        p_st_hash_node = __frct_hash_get(st_ipinfo.i_sip, st_ipinfo.i_dip, st_ipinfo.i_dport);
        if (p_st_hash_node == NULL)
        {
            p_st_hash_node = __frct_hash_get(st_ipinfo.i_dip, st_ipinfo.i_sip, st_ipinfo.i_sport);
            if (p_st_hash_node == NULL)
            {
                Frssl_hash_index *p_st_index = NULL;
                
                //hash里的内容不能过多
                if (frhash2_getCount(g_p_st_hash_ct) >= FRSSL_HASH_OVER_FLOW)
                {
                    FRLOG_WARN_LIMIT("ssl hash over flow");
                    goto err;
                }
                
                p_st_index = (Frssl_hash_index *)frmalloc(sizeof(Frssl_hash_index));
                p_st_index->i_sip = st_ipinfo.i_sip;
                p_st_index->i_dip = st_ipinfo.i_dip;
                p_st_index->i_dport = st_ipinfo.i_dport;
                p_st_index->st_time.tv_sec = header->ts.tv_sec + FRSSL_CT_TIMEOUT;
                p_st_index->st_time.tv_usec = header->ts.tv_usec;
                
                if (g_i_dssl_task_cnt == 1)
                    p_st_index->i_index = 0;
                else
                    p_st_index->i_index = __frct_get_index(st_ipinfo.i_sip, st_ipinfo.i_dip, st_ipinfo.i_dport);
                p_st_hash_node = __frct_hash_add(p_st_index, st_ipinfo.i_sip, st_ipinfo.i_dip, st_ipinfo.i_dport);
                if (p_st_hash_node == NULL)
                {
                    frfree(p_st_index);
                    goto err;
                }
                ul_lst_index = p_st_index->i_index;
                p_st_hash_node = NULL;
            }
        }
        if (p_st_hash_node)
        {
            Frssl_hash_index *p_st_hash_index = (Frssl_hash_index *)p_st_hash_node->data;
            ul_lst_index = p_st_hash_index->i_index;
            p_st_hash_index->st_time.tv_sec = header->ts.tv_sec + FRSSL_CT_TIMEOUT;
            p_st_hash_index->st_time.tv_usec = header->ts.tv_usec;
        }
    }
    //组成待处理数据
    if (frssl_mk_encode_lst(p_packet, header->caplen, i_type, &st_ipinfo, &header->ts, &p_ssl_thread) != FR_SUCC)
        goto err;
    
    //将数据分类放入链表中
    pthread_spin_lock(&g_spin_ssl_lock);
    {
        Frlist_node *p_node_tmp = NULL;
        p_node_tmp = FRLIST_FIRST_NODE(g_p_st_dssl_thread);
        
        p_st_node = frlist_node_create(p_ssl_thread);
        if(!p_st_node)
        {
            pthread_spin_unlock(&g_spin_ssl_lock);
            goto err;
        }
        while (p_node_tmp && p_node_tmp->data)
        {
            Frssl_thread_lst *p_lst_thread = (Frssl_thread_lst *)p_node_tmp->data;
            if (p_lst_thread->i_index == ul_lst_index)
            {
                //缓存队列里的内容不能过多
                if (frlist_size(p_lst_thread->p_lst_header) > FRSSL_HASH_OVER_FLOW)
                {
                    FRLOG_WARN_LIMIT("ssl list over flow");
                    pthread_spin_unlock(&g_spin_ssl_lock);
                    goto err;
                }
                frlist_push(p_lst_thread->p_lst_header, p_st_node);
                pthread_spin_unlock(&g_spin_ssl_lock);
                goto success;
            }
            p_node_tmp = FRLIST_NEXT_NODE(p_node_tmp);
        }
        pthread_spin_unlock(&g_spin_ssl_lock);
        frfree(p_st_node);
        goto err;
    }
    pthread_spin_unlock(&g_spin_ssl_lock);

success:    
    return FR_SUCC;
err:
    if (p_st_node)
        frfree(p_st_node);
    __ssl_thread_free(&p_ssl_thread);
    
    return FR_FAIL;
}


/*******************************************************************************
*  FUNC     :  执行工作任务
*  ARGS     :  
*  RTN      :  
*  NOTE     :  
*******************************************************************************/
void *frssl_task_do(void *arg)
{
    int i_index = (int)((long)arg);
    Frlist_node *p_node_tmp = NULL;
    Frlist_node *p_task_node = NULL;
    Frlist_header *p_st_task_header = NULL;

    FRLOG_DEBUG("frssl_task_do run...");
    frdbg("frssl_task_do(%lu) run...\n", pthread_self());
    
    p_node_tmp = FRLIST_FIRST_NODE(g_p_st_dssl_thread);
    while (p_node_tmp && p_node_tmp->data)
    {
        Frssl_thread_lst *p_lst_thread = (Frssl_thread_lst *)p_node_tmp->data;
        if (p_lst_thread->i_index == i_index)
        {
            p_st_task_header = p_lst_thread->p_lst_header;
            break;
        }
        p_node_tmp = FRLIST_NEXT_NODE(p_node_tmp);
    }
    if (p_st_task_header == NULL)
    {
        FRLOG_ERROR_DETAIL("task%d error", i_index);
        pthread_exit(0);
        return (void*)NULL;
    }
    
    while(g_i_flag_run)
    {
        //取得锁
        pthread_spin_lock(&g_spin_ssl_lock);
    
        p_task_node = frlist_pop(p_st_task_header);
        if (p_task_node == NULL || p_task_node->data == NULL)
        {
            pthread_spin_unlock(&g_spin_ssl_lock);
            usleep(10000);
            continue;
        }
#ifdef FRTEST_REPORT
        g_ul_parse_all++;
#endif
        //做decode处理
        pthread_spin_unlock(&g_spin_ssl_lock);
        frssl_decode((Frssl_thread *)(p_task_node->data));
        
        __thread_node_free(p_task_node);
        frfree(p_task_node);
    }
    pthread_exit(0);
    return (void*)NULL;
}

FR_STATIC int __list_node_check_done(Frlist_node *p_st_node, const void *p_data)
{
    Frssl_thread_lst *p_thread_node = NULL;

    if(p_st_node && p_st_node->data)
    {
        p_thread_node = (Frssl_thread_lst *) p_st_node->data;
        g_i_task_count += frlist_size(p_thread_node->p_lst_header);
        return 0;
    }

    return 1;
}

int frssl_task_done(void)
{
    g_i_task_count = 0;
    frlist_run(g_p_st_dssl_thread, NULL, __list_node_check_done);
    if (g_i_task_count > 0)
        return FR_FAIL;
    return FR_SUCC;
}
